package bblrtc

import (
	"encoding/json"
	"fmt"
	"github.com/boltdb/bolt"
	"time"
)

var (
	TABLE_MEMBER = []byte("rtc_member")
)

type User struct {
	Name   string
	Blocks []string
}

type RegisterDB struct {
	file string
	db   *bolt.DB
}

func NewUDB(file string) (s *RegisterDB, err error) {
	db, err := bolt.Open(file, 0600, &bolt.Options{Timeout: 30 * time.Second})
	if err != nil {
		return nil, err
	}
	err = db.Update(func(tx *bolt.Tx) error {
		if _, err := tx.CreateBucketIfNotExists(TABLE_MEMBER); err != nil {
			return err
		}
		return nil
	})
	s = &RegisterDB{db: db, file: file}
	return s, err
}

func (s *RegisterDB) Block(who, blocker string) error {
	user := s.FindUser(who)
	if user == nil {
		return fmt.Errorf("member %v not exist", who)
	}
	tx, err := s.db.Begin(true)
	if err != nil {
		return err
	}
	defer tx.Rollback()

	user.Blocks = append(user.Blocks, blocker)
	b, err := json.Marshal(user)
	if err != nil {
		return err
	}

	if err = tx.Bucket(TABLE_MEMBER).Put([]byte(who), b); err != nil {
		return err
	}

	return tx.Commit()
}

func (s *RegisterDB) AddUser(member string) error {
	tx, err := s.db.Begin(true)
	if err != nil {
		return err
	}
	defer tx.Rollback()
	u := &User{Name: member, Blocks: []string{}}
	b, err := json.Marshal(u)
	if err != nil {
		return err
	}
	if err := tx.Bucket(TABLE_MEMBER).Put([]byte(member), b); err != nil {
		return err
	}
	return tx.Commit()
}

func (s *RegisterDB) RemoveUser(member string) error {
	tx, err := s.db.Begin(true)
	if err != nil {
		return err
	}
	defer tx.Rollback()

	if err = tx.Bucket(TABLE_MEMBER).Delete([]byte(member)); err != nil {
		return err
	}

	return tx.Commit()
}

func (s *RegisterDB) FindUser(member string) (user *User) {
	user = &User{}
	err := s.db.View(func(tx *bolt.Tx) error {
		if val := tx.Bucket(TABLE_MEMBER).Get([]byte(member)); val == nil || len(val) == 0 {
			return fmt.Errorf("member %v not exist", member)
		} else {
			return json.Unmarshal(val, user)
		}
	})
	if err == nil {
		return user
	}
	return nil

}

func (s *RegisterDB) ChangeUserID(memberA, memberB string) error {
	userA := s.FindUser(memberA)
	if userA == nil {
		return fmt.Errorf("memberA %v not exist", memberA)
	}

	userB := s.FindUser(memberB)
	if userB != nil {
		return fmt.Errorf("memberB %v exist", memberB)
	}

	tx, err := s.db.Begin(true)
	if err != nil {
		return err
	}
	defer tx.Rollback()

	userA.Name = memberB

	b, err := json.Marshal(userA)
	if err != nil {
		return err
	}
	if err = tx.Bucket(TABLE_MEMBER).Put([]byte(userA.Name), b); err != nil {
		return err
	}

	return tx.Commit()
}

// func (s *IMStorage) SetSession(sid string, ss *Session) error {
// 	tx, err := s.db.Begin(true)
// 	if err != nil {
// 		return err
// 	}
// 	defer tx.Rollback()
// 	b, err := json.Marshal(ss)
// 	if err != nil {
// 		return err
// 	}
// 	err = tx.Bucket(TABLE_SESSION).Put([]byte(sid), b)
// 	if err != nil {
// 		return err
// 	}
// 	return tx.Commit()
// }

// func (s *IMStorage) GetSession(sid string) (*Session, error) {
// 	tx, err := s.db.Begin(true)
// 	if err != nil {
// 		return nil, err
// 	}
// 	defer tx.Rollback()
// 	b := tx.Bucket(TABLE_SESSION).Get([]byte(sid))
// 	ss := &Session{}
// 	err = json.Unmarshal(b, ss)
// 	if err != nil {
// 		return nil, err
// 	}
// 	if err := tx.Commit(); err != nil {
// 		return nil, err
// 	}
// 	return ss, nil
// }

// func (s *IMStorage) RemoveSession(sid string) error {
// 	tx, err := s.db.Begin(true)
// 	if err != nil {
// 		return err
// 	}
// 	defer tx.Rollback()
// 	err = tx.Bucket(TABLE_SESSION).Delete([]byte(sid))
// 	if err != nil {
// 		return err
// 	}
// 	return tx.Commit()
// }

// func (s *IMStorage) PutAttach(key string, r io.Reader) (string, error) {
// 	if err := s.ob.Put(key, r, map[string]string{}); err != nil {
// 		return "", err
// 	}
// 	return strings.Replace(s.oss_url, "$key", key, -1), nil
// }
